package com.nehc.nettyserver.netty;

import com.nehc.nettyserver.common.model.Message;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 心跳处理器
 * 处理空闲连接和心跳检测
 * 
 * @author NEHC
 */
@Slf4j
@Sharable
public class HeartbeatHandler extends ChannelInboundHandlerAdapter {
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    private int lostHeartbeats = 0;
    private static final int MAX_LOST_HEARTBEATS = 3;

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                lostHeartbeats++;
                log.debug("读空闲，已连续{}次未收到心跳", lostHeartbeats);
                
                if (lostHeartbeats >= MAX_LOST_HEARTBEATS) {
                    // 连续多次未收到心跳，断开连接
                    log.info("连续{}次未收到心跳，关闭连接", MAX_LOST_HEARTBEATS);
                    ctx.close();
                    return;
                }
                
                // 发送ping消息
                Message ping = Message.createSystemMessage("Ping");
                ping.setType(Message.Type.HEARTBEAT);
                ping.addPayload("ping", System.currentTimeMillis());
                
                try {
                    String pingJson = objectMapper.writeValueAsString(ping);
                    ctx.writeAndFlush(new TextWebSocketFrame(pingJson));
                    log.debug("发送Ping消息");
                } catch (Exception e) {
                    log.error("发送Ping消息失败", e);
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 收到任何消息都重置心跳计数
        lostHeartbeats = 0;
        
        // 继续处理消息
        ctx.fireChannelRead(msg);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("心跳处理器异常", cause);
        ctx.close();
    }
} 